package com.ruoyi.huanjing.controller;

import com.ruoyi.common.annotation.Anonymous;
import com.ruoyi.common.core.redis.RedisCache;
import com.ruoyi.common.utils.DictUtils;
import com.ruoyi.huanjing.entity.Atmospheric;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import ucar.ma2.Array;
import ucar.ma2.DataType;
import ucar.nc2.NetcdfFile;
import ucar.nc2.Variable;
import ucar.nc2.Attribute;

import java.io.IOException;
import java.math.BigDecimal;
import java.util.*;
import java.util.ArrayList;
import java.util.List;
@RestController
public class NcReadController {

    @Autowired
    private RedisCache redisCache;

    // 全局变量，用于存储经纬度数据
    private static Array globalLonData = null;
    private static Array globalLatData = null;

    /**
     * 读取HDF4/NetCDF文件中的所有变量，返回带递增ID的Map列表，包含变量名和类型
     * @param filePath 文件路径
     * @return 包含id、variable和type的Map数组，id从1开始递增
     */
    @Anonymous
    @GetMapping("/readAllVariables")
    public List<Map<String, String>> readAllVariables(@RequestParam("filePath") String filePath) {
        List<Map<String, String>> variableList = new ArrayList<>();
        int id = 1; // 递增ID计数器

        try (NetcdfFile ncFile = NetcdfFile.open(filePath)) {
            List<Variable> variables = ncFile.getVariables();

            for (Variable var : variables) {
                Map<String, String> variableInfo = new HashMap<>();
                String name = var.getShortName();
                // 如果varType不是"Geo2D"，则跳过不添加到列表
                if ("Latitude".equals(name) || "Longitude".equals(name) || "gflags".equals(name)) {
                    continue;
                }
                variableInfo.put("id",  String.valueOf(id++));
                variableInfo.put("variable", var.getFullName());
                variableInfo.put("name", name);
                variableInfo.put("label", getDictReplacedLabel(name));

                // 获取变量的维度信息
                List<ucar.nc2.Dimension> dimensions = var.getDimensions();
                // 过滤掉可能的无效维度，这里假设字符型变量不应有有效维度
                if (var.getDataType().isString()) {
                    dimensions = new ArrayList<>();
                }
                // 新增：若为结构体类型，将维度列表置空
                if (var instanceof ucar.nc2.Structure) {
                    dimensions = new ArrayList<>();
                }
                int dimCount = dimensions.size();
                StringBuilder dimInfo = new StringBuilder();
                for (int i = 0; i < dimensions.size(); i++) {
                    if (i > 0) {
                        dimInfo.append(", ");
                    }
                    ucar.nc2.Dimension dim = dimensions.get(i);
                    dimInfo.append(dim.getShortName());
                }

                // 判断变量类型，没有维度时 type 设为 "-"
                String varType;
                if (dimCount == 0 || dimensions.stream().anyMatch(d -> d.getLength() == 1)) {
                    varType = "-";
                } else {
                    // 仅当变量同时包含 "2*nscans" 和 "1KM_geo_dim" 维度时才判定为 Geo2D 类型
                    boolean has2NScans = dimensions.stream().anyMatch(d -> d.getShortName() != null && d.getShortName().equals("2*nscans") || d.getShortName().equals("lat"));
                    boolean has1KMGeoDim = dimensions.stream().anyMatch(d -> d.getShortName() != null && d.getShortName().equals("1KM_geo_dim") || d.getShortName().equals("lat"));
                    if (has2NScans && has1KMGeoDim) {
                        varType = "Geo2D";
                    } else {
                        // 假设只有两个独立有效维度时判定为2D
                        // 这里需要根据实际情况调整判断逻辑，当前为示例
                        if (dimCount >= 2) {
                            varType = "2D";
                        } else {
                            varType = dimCount + "D";
                        }
                    }
                }
                variableInfo.put("type", varType);

                if (!dimensions.isEmpty()) {
                    variableInfo.put("dimensions", dimInfo.toString());
                }
                
                // 如果varType为"-"，则跳过不添加到列表
                if ("-".equals(varType)) {
                    continue;
                }
                
                // 如果varType不是"Geo2D"，则跳过不添加到列表
                if (!"Geo2D".equals(varType)) {
                    continue;
                }
                
                variableList.add(variableInfo);
            }

        } catch (IOException e) {
            System.err.println("读取变量列表时出错: " + e.getMessage());
            e.printStackTrace();
            // 出错时返回空列表
        }

        return variableList;
    }


    @Anonymous
    @GetMapping("/readGeo2D")
    public Map<String, Object> getHeightData(String filePath, String variableName) throws IOException {
//        filePath = "E:\\localfile\\MYD021KM.A2017314.0345.061.2017314164621.hdf";
        //动态获取盘符,替代盘符
//        String disk = redisCache.getCacheObject("disk").toString();
//        filePath=disk+filePath.substring(2);
        Map<String, Object> data = readDataFromHDF(filePath,variableName);
        return data;
    }

    private Map<String, Object> readDataFromHDF(String filePath, String variableName) throws IOException {
        try (NetcdfFile ncFile = NetcdfFile.open(filePath)) {
            // 删除降采样相关代码，不再设置默认分辨率
            // 查找变量
            Variable heightVar = ncFile.findVariable(variableName);
            if (heightVar == null) {
                throw new RuntimeException("未找到 " + variableName + " 变量");
            }
            // 获取变量单位属性
            Attribute unitsAttr = heightVar.findAttribute("units");
            String units = unitsAttr != null ? unitsAttr.getStringValue() : null;
            Array heightData = heightVar.read();
            int[] shape = heightVar.getShape();
            int ySize = shape[0];
            int xSize = shape[1];

            // 定义可能的经纬度变量名
            String[] latNames = {"lat", "Lat", "latitude", "Latitude"};
            String[] lonNames = {"lon", "Lon", "longitude", "Longitude"};

            // 递归查找纬度变量
            Variable latVar = findVariableRecursively(ncFile, latNames);
            Variable lonVar = findVariableRecursively(ncFile, lonNames);

            // 经纬度数据
            Array lonData;
            Array latData;

            // 如果未找到经纬度变量，则生成默认数据
            if (latVar == null || lonVar == null) {
                System.out.println("未找到经纬度变量，使用默认生成的经纬度");

                // 与Python代码保持一致，使用0.05度网格
                // 创建一维经度数组 (-180+0.025 到 180-0.025)
                double[] lonArray = new double[xSize];
                double lonStep = 0.05; // Python代码中使用的0.05度分辨率
                for (int i = 0; i < xSize; i++) {
                    lonArray[i] = -180 + 0.025 + i * lonStep;
                    // 确保不超过180-0.025
                    if (lonArray[i] > 180 - 0.025) lonArray[i] = 180 - 0.025;
                }
                lonData = Array.factory(DataType.DOUBLE, new int[]{xSize}, lonArray);

                // 创建一维纬度数组 (90-0.025 到 -90+0.025)
                double[] latArray = new double[ySize];
                double latStep = 0.05; // Python代码中使用的0.05度分辨率
                for (int i = 0; i < ySize; i++) {
                    latArray[i] = 90 - 0.025 - i * latStep;
                    // 确保不低于-90+0.025
                    if (latArray[i] < -90 + 0.025) latArray[i] = -90 + 0.025;
                }
                latData = Array.factory(DataType.DOUBLE, new int[]{ySize}, latArray);
            } else {
                return readDataFromHDFIsLatLon(filePath, variableName);
            }

            // 创建结果集合和边界追踪变量
            List<Atmospheric> atmosphericList = new ArrayList<>();
            double minLon = Double.MAX_VALUE;
            double maxLon = Double.MIN_VALUE;
            double minLat = Double.MAX_VALUE;
            double maxLat = Double.MIN_VALUE;
            double minValue = Double.MAX_VALUE;
            double maxValue = Double.MIN_VALUE;

            // 确定有效的循环边界
            int loopYSize = Math.min(ySize, latData.getShape()[0]);
            int loopXSize = Math.min(xSize, lonData.getShape()[0]);

            // 获取变量的属性
            Attribute scaleFactorAttr = heightVar.findAttribute("scale_factor");
            double scaleFactor = scaleFactorAttr != null ? scaleFactorAttr.getNumericValue().doubleValue() : 1.0;

            Attribute addOffsetAttr = heightVar.findAttribute("add_offset");
            double addOffset = addOffsetAttr != null ? addOffsetAttr.getNumericValue().doubleValue() : 0.0;

            Attribute fillValueAttr = heightVar.findAttribute("_FillValue");
            short fillValue = fillValueAttr != null ? fillValueAttr.getNumericValue().shortValue() : 0;

            // 降采样步长 (1度 / 0.05度 = 20)
            int downsampleStep = 100;

            for (int y = 0; y < loopYSize; y += downsampleStep) {
                for (int x = 0; x < loopXSize; x += downsampleStep) {
                    // 读取经纬度值
                    double lon, lat;
                    int[] lonShape = lonData.getShape();
                    int[] latShape = latData.getShape();

                    // 处理经度
                    if (lonShape.length == 1) {
                        // 一维经度数组
                        lon = lonData.getDouble(lonData.getIndex().set(x));
                    } else if (lonShape.length == 2) {
                        // 二维经度数组
                        lon = lonData.getDouble(lonData.getIndex().set(y, x));
                    } else {
                        throw new IllegalArgumentException("不支持的经度数组维度: " + lonShape.length);
                    }

                    // 处理纬度
                    if (latShape.length == 1) {
                        // 一维纬度数组
                        lat = latData.getDouble(latData.getIndex().set(y));
                    } else if (latShape.length == 2) {
                        // 二维纬度数组
                        lat = latData.getDouble(latData.getIndex().set(y, x));
                    } else {
                        throw new IllegalArgumentException("不支持的纬度数组维度: " + latShape.length);
                    }

                    // 读取原始值
                    short value = heightData.getShort(heightData.getIndex().set(y, x));

                    // 检查是否为填充值
                    if (fillValueAttr != null && value == fillValue) {
                        continue; // 跳过填充值
                    }

                    // 应用缩放和偏移
                    double finalValue = value * scaleFactor + addOffset;

                    // 更新边界
                    minLon = Math.min(minLon, lon);
                    maxLon = Math.max(maxLon, lon);
                    minLat = Math.min(minLat, lat);
                    maxLat = Math.max(maxLat, lat);
                    minValue = Math.min(minValue, finalValue);
                    maxValue = Math.max(maxValue, finalValue);

                    Atmospheric atmospheric = new Atmospheric();
                    atmospheric.setLon(BigDecimal.valueOf(lon));
                    atmospheric.setLat(BigDecimal.valueOf(lat));
                    atmospheric.setValue(BigDecimal.valueOf(finalValue));
                    atmosphericList.add(atmospheric);
                }
            }
            System.out.println("atmosphericList.size() = " + atmosphericList.size());

            // 封装结果
            Map<String, Object> result = new HashMap<>();
            result.put("dataList", atmosphericList);
            // 添加单位信息到结果
            result.put("units", units);

            Map<String, Double> bounds = new HashMap<>();
            bounds.put("minLon", minLon);
            bounds.put("maxLon", maxLon);
            bounds.put("minLat", minLat);
            bounds.put("maxLat", maxLat);
            result.put("bounds", bounds);

            // 添加数据值的最大值和最小值
            Map<String, Double> valueRange = new HashMap<>();
            valueRange.put("minValue", minValue);
            valueRange.put("maxValue", maxValue);
            result.put("valueRange", valueRange);

            return result;
        }
    }


    private Map<String, Object> readDataFromHDFIsLatLon(String filePath, String variableName) throws IOException {
        try (NetcdfFile ncFile = NetcdfFile.open(filePath)) {
            // 查找变量
            Variable heightVar = ncFile.findVariable(variableName);
            if (heightVar == null) {
                throw new RuntimeException("未找到 " + variableName + " 变量");
            }
            // 获取变量单位属性
            Attribute unitsAttr = heightVar.findAttribute("units");
            String units = unitsAttr != null ? unitsAttr.getStringValue() : null;
            Array heightData = heightVar.read();
            int[] shape = heightVar.getShape();
            int ySize = shape[0];
            int xSize = shape[1];

            // 定义可能的经纬度变量名
            String[] latNames = {"lat", "Lat", "latitude", "Latitude"};
            String[] lonNames = {"lon", "Lon", "longitude", "Longitude"};

            // 递归查找纬度变量
            Variable latVar = findVariableRecursively(ncFile, latNames);
            if (latVar == null) {
                throw new RuntimeException("未找到纬度变量，尝试查找的变量名：" + String.join(", ", latNames));
            }

            // 递归查找经度变量
            Variable lonVar = findVariableRecursively(ncFile, lonNames);
            if (lonVar == null) {
                throw new RuntimeException("未找到经度变量，尝试查找的变量名：" + String.join(", ", lonNames));
            }

            // 读取经纬度数据
            Array lonData = lonVar.read();
            Array latData = latVar.read();

            // 创建结果集合和边界追踪变量
            List<Atmospheric> atmosphericList = new ArrayList<>();
            Set<String> coordinateSet = new HashSet<>();
            double minLon = Double.MAX_VALUE;
            double maxLon = Double.MIN_VALUE;
            double minLat = Double.MAX_VALUE;
            double maxLat = Double.MIN_VALUE;
            double minValue = Double.MAX_VALUE;
            double maxValue = Double.MIN_VALUE;

            for (int y = 0; y < ySize; y++) {
                for (int x = 0; x < xSize; x++) {
                    // 读取经纬度值
                    double lon = lonData.getDouble(lonData.getIndex().set(y, x));
                    double lat = latData.getDouble(latData.getIndex().set(y, x));
                    short value = heightData.getShort(heightData.getIndex().set(y, x));

                    // 只保留整数部分
                    int intLon = (int) lon;
                    int intLat = (int) lat;
                    String coordinateKey = intLon + "," + intLat;

                    // 处理无效值，根据 valid_range 和 _FillValue 过滤
                    if (/*value != -32767 && value >= -400 && value <= 10000 && */!coordinateSet.contains(coordinateKey)) {
                        // 更新边界
                        minLon = Math.min(minLon, intLon);
                        maxLon = Math.max(maxLon, intLon);
                        minLat = Math.min(minLat, intLat);
                        maxLat = Math.max(maxLat, intLat);
                        minValue = Math.min(minValue, value);
                        maxValue = Math.max(maxValue, value);

                        Atmospheric atmospheric = new Atmospheric();
                        atmospheric.setLon(BigDecimal.valueOf(intLon));
                        atmospheric.setLat(BigDecimal.valueOf(intLat));
                        atmospheric.setValue(BigDecimal.valueOf(value));
                        atmosphericList.add(atmospheric);
                        coordinateSet.add(coordinateKey);
                    }
                }
            }
            System.out.println("atmosphericList.size() = " + atmosphericList.size());

            // 封装结果
            Map<String, Object> result = new HashMap<>();
            result.put("dataList", atmosphericList);
            // 添加单位信息到结果
            result.put("units", units);

            Map<String, Double> bounds = new HashMap<>();
            bounds.put("minLon", minLon);
            bounds.put("maxLon", maxLon);
            bounds.put("minLat", minLat);
            bounds.put("maxLat", maxLat);
            result.put("bounds", bounds);

            // 添加数据值的最大值和最小值
            Map<String, Double> valueRange = new HashMap<>();
            valueRange.put("minValue", minValue);
            valueRange.put("maxValue", maxValue);
            result.put("valueRange", valueRange);

            return result;
        }
    }

    // 递归查找变量的方法
    private Variable findVariableRecursively(NetcdfFile ncFile, String[] names) {
        List<Variable> allVariables = new ArrayList<>();
        collectAllVariables(ncFile.getRootGroup(), allVariables);

        for (Variable var : allVariables) {
            for (String name : names) {
                if (var.getShortName().equalsIgnoreCase(name)) {
                    return var;
                }
            }
        }
        return null;
    }

    // 递归收集所有变量的方法
    private void collectAllVariables(ucar.nc2.Group group, List<Variable> variables) {
        variables.addAll(group.getVariables());
        for (ucar.nc2.Group subgroup : group.getGroups()) {
            collectAllVariables(subgroup, variables);
        }
    }

    // 封装字典替换逻辑
    private String getDictReplacedLabel(String name) {
        String dictValue = DictUtils.getDictLabel("hj_bl", name);
        return dictValue != null && !dictValue.isEmpty() ? dictValue : name;
    }
}
